#include <string>
#include "operatorbinary.h"
#include "node.h"

extern void yyerror(const char*);

namespace AST {

    // Construtor Padrão
    OperatorBinary::OperatorBinary(std::string* content, Node* left, Node* right) {
        // Configuração Inicial
        this->_setContent(content)->_setLeft(left)->_setRight(right);
    };

    // Configuração do Conteúdo do Operador
    OperatorBinary* OperatorBinary::_setContent(std::string* content) {
        // Configuração
        this->_content = content;
        // Encadeamento
        return this;
    };

    // Configuração de Operando Esquerdo
    OperatorBinary* OperatorBinary::_setLeft(Node* left) {
        // Configuração
        this->_left = left;
        // Encadeamento
        return this;
    };

    // Configuração de Operando Direito
    OperatorBinary* OperatorBinary::_setRight(Node* right) {
        // Configuração
        this->_right = right;
        // Encadeamento
        return this;
    };

    // Apresentação de Conteúdo
    std::string* OperatorBinary::getContent() {
        // Apresentação
        return this->_content;
    };

    // Apresentação de Operando Esquerdo
    Node* OperatorBinary::getLeft() {
        // Apresentação
        return this->_left;
    };

    // Apresentação de Operando Direito
    Node* OperatorBinary::getRight() {
        // Apresentação
        return this->_right;
    };

    // Sobrescrita
    std::string OperatorBinary::toString(int indent) {
        // Apresentação
        return this->getIndentSpaces(indent)
            + "Operator '" + (*this->getContent()) + "'\n"
            + this->getLeft()->toString(indent + 1) + "\n"
            + this->getRight()->toString(indent + 1);
    };

    // Sobrescrita
    Node* OperatorBinary::check() {
        // Tipos Internos
        Type* lft = this->getLeft()->getType();
        Type* rgt = this->getRight()->getType();
        // Não Aceitar Conjunto de Dados
        if (lft->getIsArray() || rgt->getIsArray()) {
            // Erro Encontrado
            yyerror("OperatorBinary > Array");
        }
        // Somente Inteiros ou Ponto Flutuante
        if (!((lft->getContent() == AST::Type::INTEGER
            || lft->getContent() == AST::Type::FLOAT)
            && (rgt->getContent() == AST::Type::INTEGER
                || rgt->getContent() == AST::Type::FLOAT))) {
            yyerror("OperatorBinary > Unknown");
        }
        // Verificação
        std::string content = *this->getContent();
        if ((content == "==" || content == "<=" || content == ">="
            || content == "<" || content == ">" || content == "&&"
            || content == "||") &&
            !(lft->getContent() == AST::Type::INTEGER
                && rgt->getContent() == AST::Type::INTEGER)) {
            yyerror("OperatorBinary > Integer");
        }
        // Configuração
        if (lft->getContent() == AST::Type::INTEGER
            && rgt->getContent() == AST::Type::INTEGER) {
            // Resultado Inteiro
            this->setType(new AST::Type(AST::Type::INTEGER));
        } else {
            // Resultado Flutuante
            this->setType(new AST::Type(AST::Type::FLOAT));
        }
        return this;
    };

};

